#include "systemconfig.h"
#include <iostream>

using namespace std;
namespace HIM {
bool SystemConfig::loadfile(const std::string &path)
{
    SI_Error rc;
    rc = ini.LoadFile(path.c_str());
    if (rc < 0) {
        throw ConfigException(error_info(path+"Failed to load ini file:",rc));
        return false;
    }
    return true;
}

bool SystemConfig::saveFile(const std::string &fileName)
{
    SI_Error rc = ini.SaveFile(fileName.c_str());
    if (rc < 0) {
        throw ConfigException(error_info(fileName+"Failed to save ini file:",rc));
        return false;
    }
    return true;
}

void SystemConfig::setUnicode(const bool utf8)
{
    ini.SetUnicode(utf8);
}

void SystemConfig::setMultiKey(const bool multKey)
{
    ini.SetMultiKey(multKey);
}

std::string SystemConfig::getIniStr()
{
    std::string str = "";
    SI_Error rc = ini.Save(str);
    if (rc < 0)
        throw ConfigException(error_info("Failed to retrieve ini file string:",rc));
    return str;
}

/*add*/
bool SystemConfig::addSection(const std::string & section)
{
    SI_Error rc = ini.SetValue(section.c_str(), nullptr, nullptr);
    if (rc < 0) {
        throw ConfigException(error_info(section+" Node addition failed:",rc));
        return false;
    }
    return true;
}

bool SystemConfig::addValue(const std::string & section, const std::string & key, const std::string & value)
{
    SI_Error rc = ini.SetValue(section.c_str(), key.c_str(), value.c_str());
    if (rc < 0) {
        throw ConfigException(error_info(key+"="+value+"Add failed:",rc));
        return false;
    }
    return true;
}

bool SystemConfig::addLongValue(const std::string & section, const std::string & key, const long value)
{
    SI_Error rc = ini.SetLongValue(section.c_str(), key.c_str(), value);
    if (rc < 0) {
        throw ConfigException(error_info(key+"="+std::to_string(value)+"Add failed:",rc));
        return false;
    }

    return true;
}

bool SystemConfig::addDoubleValue(const std::string & section, const std::string & key, const double value)
{
    SI_Error rc = ini.SetDoubleValue(section.c_str(), key.c_str(), value);
    if (rc < 0) {
        throw ConfigException(error_info(key+"="+std::to_string(value)+"Add failed:",rc));
        return false;
    }
    return true;
}

bool SystemConfig::addBoolValue(const std::string & section, const std::string & key, const bool value)
{
    SI_Error rc = ini.SetBoolValue(section.c_str(), key.c_str(), value);
    if (rc < 0) {
        throw ConfigException(error_info(key+"="+std::to_string(value)+"Add failed:",rc));
        return false;
    }
    return true;
}

/*deleter*/
bool SystemConfig::deleteKey(const std::string & section, const std::string & key)
{
    bool done = false;
    done = ini.Delete(section.c_str(), key.c_str());
    if (false == done) {
        throw ConfigException(section+"-"+key+"Delete failed");
        return false;
    }
    return true;
}

bool SystemConfig::deleteKeys(const std::string & section, const std::string & key, const bool deleteSectionIfEmpty)
{
    bool done = false;
    done = ini.Delete(section.c_str(), key.c_str(), deleteSectionIfEmpty);
    if (false == done) {
        throw ConfigException(section+"-"+key+"Delete failed");
        return false;
    }
    return true;
}

bool SystemConfig::deleteSection(const std::string & section)
{
    bool done = false;
    done = ini.Delete(section.c_str(), nullptr);
    if (false == done) {
        throw ConfigException(section+"Delete failed");
        return false;
    }
    return true;
}

/*set*/
bool SystemConfig::setValue(const std::string & section, const std::string & key, const std::string & value)
{
    SI_Error rc = ini.SetValue(section.c_str(), key.c_str(), value.c_str());
    if (rc < 0) {
        throw ConfigException(key+"-"+value+"Modification failed");
        return false;
    }
    return true;
}

bool SystemConfig::setLongValue(const std::string & section, const std::string & key, const long value)
{
    SI_Error rc = ini.SetLongValue(section.c_str(), key.c_str(), value);
    if (rc < 0) {
        throw ConfigException(key+"-"+std::to_string(value)+"Modification failed");
        return false;
    }
    return true;
}

bool SystemConfig::setDoubleValue(const std::string & section, const std::string & key, const double value)
{
    SI_Error rc = ini.SetDoubleValue(section.c_str(), key.c_str(), value);
    if (rc < 0) {
        throw ConfigException(key+"-"+std::to_string(value)+"Modification failed");
        return false;
    }
    return true;
}

bool SystemConfig::setBoolValue(const std::string & section, const std::string & key, const bool value)
{
    SI_Error rc = ini.SetBoolValue(section.c_str(), key.c_str(), value);
    if (rc < 0) {
        throw ConfigException(key+"-"+std::to_string(value)+"Modification failed");
        return false;
    }
    return true;
}

/*get*/
std::string SystemConfig::getValue(const std::string & section, const std::string & key, const std::string & defualtValue)
{
    return  ini.GetValue(section.c_str(), key.c_str(), defualtValue.c_str());
}

char SystemConfig::getValueC(const std::string & section, const std::string & key, const char & defualtValue)
{
    std::string str = std::to_string(defualtValue);
    return  ini.GetValue(section.c_str(), key.c_str(), str.c_str())[0];
}

long SystemConfig::getLongValue(const std::string & section, const std::string & key, const short & defualtValue)
{
    return  ini.GetLongValue(section.c_str(), key.c_str(), defualtValue);
}

double SystemConfig::getDoubleValue(const std::string & section, const std::string & key, const double & defualtValue)
{
    return  ini.GetDoubleValue(section.c_str(), key.c_str(), defualtValue);
}

bool SystemConfig::getBoolValue(const std::string & section, const std::string & key, const bool & defualtValue)
{
    return  ini.GetBoolValue(section.c_str(), key.c_str(), defualtValue);
}

int SystemConfig::getSectionSize(const std::string & section)
{
    return ini.GetSectionSize(section.c_str());
}

void SystemConfig::printAll()
{
    CSimpleIniA::TNamesDepend sections;
    ini.GetAllSections(sections);
    for (const auto &it : sections) {
        const CSimpleIniA::TKeyVal *pKeyVal = ini.GetSection(it.pItem);
        if (nullptr != pKeyVal) {
            for (const auto& it : *pKeyVal) {
                std::cout << it.first.pItem << " = " << it.second << std::endl;
            }
        }
    }
}

string SystemConfig::error_info(const string& cs,int errnum)
{
    string err;
    switch (errnum) {
    case SI_FAIL:
        err = "Illegal function";
        break;
    case SI_NOMEM:
        err =  "Illegal data address";
        break;
    case SI_FILE:
    default:
        err =  strerror(errnum);
        break;
    }
    return cs+err;
}

}
